﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace FontTool
{
    public partial class FontToolMain
    {
        #region preview window variables
        Bitmap offScreenBmp;
        Graphics gfx;
        //shows if previewWindow (bottom left) is maximized or not
        bool b_previewMaximized = false;
        Font fFont = new Font("Arial", 7);
        //Rectangle surrounding the text in the preview window
        public RectangleF previewTextRect = new RectangleF(0, 0, 0, 600);

        public string imgUri = "";
        public Image background;
        public Rectangle backgroundRect = new Rectangle();

        public Bitmap imgTiles;
        public Image bmpBGTiles;

        public Bitmap imgError = Properties.Resources.error;


        private bool previewdefault = true;
        public bool previewDefault
        {
            get { return previewdefault; }
            set
            {
                previewdefault = value;
                _SpaceBeginLocation = 0;
                _KerningBeginLocation = 0;
            }
        }
        public float newPreviewX = 0;
        public bool renameTopLine = true;
        public bool previewFocused = false;
        public bool drawPreviewRect = false;

        Point bgPoint;
        #endregion

        #region Preview draw
        /*
         * Preview window handling;
         * We take text as an input
         * split all chars into [];
         * based on chars into hex's;
         * use hex to get required images;
         * draw those images in previewWindow
         * !!WILL NEED TO MODIFY IT TO MAKE IT DRAW BASED ON PARAMETERS AND NOT! MY HARD-CODED VALUES
         */
        private void drawPreviewWindow(string lineOne, bool firstLine)
        {

            //bool newSpaceLocation = false;
            //bool newKerningLocation = false;
            //creating a list of strings where we are storring all the hex values needed
            string[] lineOneHex = new string[lineOne.Length];

            for (int i = 0; i < lineOne.Length; i++)
            {
                char c = lineOne[i];
                int unicode = c;
                lineOneHex[i] = string.Format("0x{0:x4}", unicode);
            }

            #region measure string
            float textLength = _base.Location.X;
            foreach (string s in lineOneHex)
            {
                if (newFont.containsCharHEX(s) || "0x0020" == s)
                {
                    for (int i = 0; i < newFont._Characters.Count; i++)
                    {
                        if (newFont._Characters[i]._Name == s)
                        {
                            textLength += (newFont._Kerning - newFont._Characters[i]._AnchorPoint.X + newFont._Characters[i]._Width);
                            break;
                        }
                        //space hex
                        if ("0x0020" == s)
                        {
                            textLength += newFont._Space;
                            break;
                        }
                    }
                }
                else if (!newFont.containsCharHEX(s))
                {
                    textLength += imgError.Width;
                }

            }
            #endregion

            #region allignment
            float X = 0;
            if (newFont.textAlignment == nFont.textAlign.Center)
            {
                if (previewDefault)
                    X = (panelPreview.Width - textLength) / 2;
                if (!previewDefault)
                    X = newPreviewX - (textLength / 2);
            }

            if (newFont.textAlignment == nFont.textAlign.Left)
            {
                if (previewDefault)
                    X = panelPreview.Location.X;
                if (!previewDefault)
                    X = newPreviewX;
            }

            if (newFont.textAlignment == nFont.textAlign.Right)
            {
                if (previewDefault)
                    X = (panelPreview.Width - textLength);
                if (!previewDefault)
                    X = newPreviewX - textLength;
            }

            if (previewTextRect.Width <= textLength)
            {
                previewTextRect.Width = textLength;
                previewTextRect.X = X;
                previewTextRect.Y = _ascenderHeight.Location.Y;
                previewTextRect.Height = _multiBase.Location.Y - previewTextRect.Y;
            }
            #endregion

            //last step - drawing it actually into panelPreview;
            foreach (string s in lineOneHex)
            {
                if (newFont.containsCharHEX(s) || "0x0020" == s)
                {
                    for (int i = 0; i < newFont._Characters.Count; i++)
                    {
                        if (newFont._Characters[i]._Name == s)
                        {
                            // (newFont._Characters[i]._Height - newFont._Characters[i]._AnchorPoint.Y);
                            float Y = _base.Location.Y - newFont._Characters[i]._AnchorPoint.Y;

                            if (!firstLine)
                            {
                                Y += newFont._ascenderHeight + newFont._descenderHeight + newFont._Leading;
                            }

                            PointF pToDraw = new PointF(X, Y);
                            gfx.DrawImage(Bitmap.FromFile(newFont._Characters[i]._ImageUri), pToDraw);
                            X += (newFont._Kerning - newFont._Characters[i]._AnchorPoint.X + newFont._Characters[i]._Width);

                            //init kerning lines location
                            if (_KerningBeginLocation == 0)
                                _KerningBeginLocation = X;
                            break;
                        }
                        //space hex
                        if ("0x0020" == s)
                        {
                            if (_SpaceBeginLocation == 0)
                                _SpaceBeginLocation = X;
                            X += newFont._Space;
                            break;
                        }
                    }
                }
                else if (!newFont.containsCharHEX(s))
                {
                    float Y = _base.Location.Y - imgError.Height;

                    if (!firstLine)
                    {
                        Y += newFont._ascenderHeight + newFont._descenderHeight + newFont._Leading;
                    }
                    PointF pToDraw = new PointF(X, Y);
                    gfx.DrawImage(imgError, pToDraw);
                    X += (newFont._Kerning + imgError.Width);
                }
            }
        }

        public void drawMultiLines()
        {
            drawPreviewWindow(newFont.Message, true);
            drawPreviewWindow(newFont.MessageTwo, false);
        }
        #endregion

        #region Preview update
        /*
         * The purpose is to handle misplaced windows form once it's been changed
         * after being modified \ maximized;
         */
        private void updatePreviewSize()
        {
            if (!b_previewMaximized)
            {
                splitContainer1.Panel1Collapsed = true;
                b_previewMaximized = true;
            }

            else
            {
                splitContainer1.Panel1Collapsed = false;
                b_previewMaximized = false;
            }
        }

        private void UpdatePreviewWindow()
        {
            Graphics gx = panelPreview.CreateGraphics();

            gfx.Clear(newFont.Background);

            if (newFont.useBackground && imgUri != "")
                drawBackground();

            if (newFont.useTileBackground && imgTiles != null)
            {
                gfx.DrawImage(imgTiles, panelPreview.DisplayRectangle);
            }

            //if (drawPreviewRect)
            //{
            //    gfx.DrawRectangle(new Pen(Color.Black), previewTextRect.X, previewTextRect.Y, previewTextRect.Width, previewTextRect.Height);
            //}
            //reinitialization to make them with the latest parameters
            LinesInitHorizontal();
            drawMultiLines();
            initVerticalLines();
            UpdateLines(gfx);

            gx.DrawImage(offScreenBmp, 0, 0);
            propertyGrid1.Refresh();
            //using (Graphics gf = panelPreview.CreateGraphics())
            //{
            //    gf.DrawRectangle(new Pen(Color.Black), previewRect.X, previewRect.Y, previewRect.Width, previewRect.Height);
            //}
        }

        private void drawBackground()
        {
            gfx.DrawImage(background, bgPoint);
        }
        #endregion

        #region panelPreview button_Click
        private void buttonSetBackground_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    imgUri = ofd.FileName;
                    background = Image.FromFile(imgUri);
                    bgPoint = new Point((panelPreview.Width - background.Width) / 2, (panelPreview.Height - background.Height) / 2);
                    newFont.useBackground = true;
                    newFont.useTileBackground = false;
                    UpdatePreviewWindow();
                }
            }
        }

        private void buttonBGTiles_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    bmpBGTiles = Bitmap.FromFile(ofd.FileName);
                    initImgTiles();
                    UpdatePreviewWindow();
                }
            }
        }

        private void initImgTiles()
        {
            imgTiles = new Bitmap(panelPreview.Width, panelPreview.Height);
            int squaresAcross = panelPreview.Width / bmpBGTiles.Width + 1;
            int squaresDown = panelPreview.Height / bmpBGTiles.Height + 1;

            using (Graphics gf = Graphics.FromImage(imgTiles))
            {
                for (int y = 0; y < squaresDown; y++)
                    for (int x = 0; x < squaresAcross; x++)
                        gf.DrawImage(bmpBGTiles, new Point(x * bmpBGTiles.Width, y * bmpBGTiles.Height));
            }
            newFont.useTileBackground = true;
            newFont.useBackground = false;
        }

        private void buttonORIGIN_Click(object sender, EventArgs e)
        {
            if(background != null)
                bgPoint = new Point((panelPreview.Width - background.Width) / 2, (panelPreview.Height - background.Height) / 2);
            gfx.ResetTransform();
            previewDefault = true;
            UpdatePreviewWindow();
        }

        private void buttonMaximizePreview_Click(object sender, EventArgs e)
        {
            /*
             * Maximize the preview window button;
             * By clicking it, it will open new window in which the preview will be maximized and will have better 
             * visual view for editing font properties;
             */
            updatePreviewSize();
            offScreenBmp = new Bitmap(panelPreview.Width, panelPreview.Height);
            gfx = Graphics.FromImage(offScreenBmp);
            bgPoint = new Point((panelPreview.Width - background.Width) / 2, (panelPreview.Height - background.Height) / 2);

            if(imgTiles != null)
                initImgTiles();
            timerUpdatePreview.Start();
        }

        private void buttonWriteOnPreview_Click(object sender, EventArgs e)
        {
            
        }

        private void buttonLinesVisible_Click(object sender, EventArgs e)
        {
            drawLines = !drawLines;
            newFont.drawAllLines(drawLines);
            UpdatePreviewWindow();
        }
        #endregion

        #region panel preview mouse events (Click,Down,Move,Up,Wheel)
        private void panelPreview_Click(object sender, EventArgs e)
        {
            previewFocused = true;
            panelPreview.Focus();
        }

        void panelPreview_MouseWheel(object sender, MouseEventArgs e)
        {
            if (newFont == null)
                return;
            //checking delta(mouse wheel up or down);
            //based on that either we incr or decr 10% image scale;
            if (e.Delta > 0)
            {
                imageScale = imageScaleIncr;
                imageScaleWrite *= imageScaleIncr;
            }
            if (e.Delta < 0)
            {
                imageScale = imageScaleDescr;
                imageScaleWrite *= imageScaleDescr;
            }

            gfx.TranslateTransform(e.X, e.Y);
            gfx.ScaleTransform(imageScale, imageScale);
            gfx.TranslateTransform(-e.X, -e.Y);
            UpdatePreviewWindow();

            using (Graphics gf = panelPreview.CreateGraphics())
            {
                gf.DrawString((Math.Round(imageScaleWrite, 2) * 100).ToString() + "%", fFont, new SolidBrush(Color.Black), new PointF(1, 1));
            }
        }

        private void panelPreview_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (overTheLine(e.Location))
                {
                    checkLinesIntersection(e.Location);
                    this.Cursor = Cursors.Hand;
                    panelPreview.MouseUp += new MouseEventHandler(panelPreview_MouseUpLine);
                    panelPreview.MouseMove += new MouseEventHandler(panelPreview_MouseMoveLine);
                }
                else
                {
                    if (newFont.useBackground)
                    {
                        this.Cursor = Cursors.Hand;
                        panelPreview.MouseUp += new MouseEventHandler(panelPreview_MouseUpMoveBG);
                        panelPreview.MouseMove += new MouseEventHandler(panelPreview_MouseMoveMoveBG);
                    }
                }

            }
        }

        void panelPreview_MouseMoveMoveBG(object sender, MouseEventArgs e)
        {
            //background top corner: bgPoint
            //Mouse location: e.Location
            bgPoint = new Point(e.X- background.Width/2, e.Y - background.Height/2);

            UpdatePreviewWindow();
            panelPreview.Focus();
        }

        void panelPreview_MouseUpMoveBG(object sender, MouseEventArgs e)
        {
            panelPreview.MouseMove -= new MouseEventHandler(panelPreview_MouseMoveMoveBG);
            panelPreview.MouseUp -= new MouseEventHandler(panelPreview_MouseUpMoveBG);
            this.Cursor = Cursors.Default;
        }
        #endregion

        #region move preview one line mouseMove & mouseUP
        void panelPreview_MouseMoveLine(object sender, MouseEventArgs e)
        {
            if (_Leading.movable)
                newFont.Leading = e.Y - (_base.Location.Y + newFont._descenderHeight);

            if (_xHeight.movable)
                if (_base.Location.Y - e.Y >= 0)
                    newFont.xHeight = _base.Location.Y - e.Y;

            if (_capHeight.movable)
                if (_base.Location.Y - e.Y >= 0)
                    newFont.capHeight = _base.Location.Y - e.Y;

            if (_ascenderHeight.movable)
                if (_base.Location.Y - e.Y >= 0)
                    newFont.ascenderHeight = _base.Location.Y - e.Y;

            if (_descenderHeight.movable)
                if (e.Y - _base.Location.Y >= 0)
                    newFont.descenderHeight = e.Y - _base.Location.Y;

            UpdatePreviewWindow();
            panelPreview.Focus();
        }

        void panelPreview_MouseUpLine(object sender, MouseEventArgs e)
        {
            panelPreview.MouseMove -= new MouseEventHandler(panelPreview_MouseMoveLine);
            panelPreview.MouseUp -= new MouseEventHandler(panelPreview_MouseUpLine);
            setAllLinesUnmovable();
            this.Cursor = Cursors.Default;
            panelPreview.Focus();
        }
        #endregion

        void panelPreview_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyData == Keys.Up)
            {
                moveLine(true);
            }
            if (e.KeyData == Keys.Down)
            {
                moveLine(false);
            }
        }

        private void updateZoom(float zoom)
        {
            previewContextMenu.Visible = false;
            imageScale = zoom;

            gfx.ResetTransform();
            gfx.TranslateTransform((panelPreview.Width) / 2, (panelPreview.Height) / 2);
            gfx.ScaleTransform(imageScale, imageScale);
            gfx.TranslateTransform(-(panelPreview.Width) / 2, -(panelPreview.Height) / 2);

            timerUpdatePreview.Start();
        }

        void previewContextMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            switch (e.ClickedItem.Text)
            {
                case "25%":
                    updateZoom(0.25f);
                    break;
                case "50%":
                    updateZoom(.5f);
                    break;
                case "75%":
                    updateZoom(.75f);
                    break;
                case "100%":
                    updateZoom(1f);
                    break;
                case "125%":
                    updateZoom(1.25f);
                    break;
                case "150%":
                    updateZoom(1.5f);
                    break;
                case "175%":
                    updateZoom(1.75f);
                    break;
                case "200%":
                    updateZoom(2f);
                    break;
                default:
                    break;
            }
        }
    }
}
